/**
 * 
 */
package cz.cvut.fit.bugtrac.chart;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.googlecode.charts4j.AxisLabels;
import com.googlecode.charts4j.AxisLabelsFactory;
import com.googlecode.charts4j.Color;
import com.googlecode.charts4j.DataUtil;
import com.googlecode.charts4j.GChart;
import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.Line;
import com.googlecode.charts4j.LineChart;
import com.googlecode.charts4j.Plots;
import com.googlecode.charts4j.Shape;

import cz.cvut.fit.bugtrac.dao.GraphDAO;
import cz.cvut.fit.bugtrac.exception.BugTracException;
import cz.cvut.fit.bugtrac.publicmodel.dto.graph.GraphDTO;
import cz.cvut.fit.bugtrac.util.DozerUtil;

/**
 * @author Jarec
 * 
 */
@Component
public class ChartServiceImpl implements ChartService {

	private static transient final Logger log = Logger
			.getLogger(ChartServiceImpl.class.getName());

	private Integer width;
	private Integer height;
	private Integer ymax;
	private Integer ypart;

	private GraphDAO graphDAO;
	private DozerUtil dozerUtil;

	/*
	 * (non-Javadoc)
	 * 
	 * @see cz.cvut.fit.bugtrac.chart.CharService#getChartUrl()
	 */
	@Override
	public URL getChartUrl() throws MalformedURLException, URISyntaxException,
			BugTracException {

		GChart chart = chartConstructor();

		log.info(String
				.format("Width: %d, Height: %d", getWidth(), getHeight()));
		chart.setSize(getWidth(), getHeight());

		String chartUrl = chart.toURLString();
		URL url = new URL(chartUrl);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(),
				url.getQuery(), null);
		return uri.toURL();
	}

	/**
	 * constructs google chart - using chart4j library
	 * 
	 * @return
	 * @throws BugTracException
	 */
	private GChart chartConstructor() throws BugTracException {

		Collection<GraphDTO> graph = graphDAO.getSnapshotsDTO();
		List<String> dates = new ArrayList<String>();
		List<Integer> nodes = new ArrayList<Integer>();
		List<Integer> edges = new ArrayList<Integer>();

		DateFormat df = new SimpleDateFormat("dd.MM.");

		for (GraphDTO graphDTO : graph) {
			dates.add(df.format(graphDTO.getCreated()));
			nodes.add(graphDTO.getSize());
			edges.add(graphDTO.getEdgeSize());
		}

		Line line1 = Plots.newLine(
				DataUtil.scaleWithinRange(0, getYmax(), nodes), Color.RED,
				"nodes");
		line1.addShapeMarkers(Shape.DIAMOND, Color.RED, 12);
		line1.addShapeMarkers(Shape.DIAMOND, Color.WHITE, 8);
		Line line2 = Plots.newLine(
				DataUtil.scaleWithinRange(0, getYmax(), edges), Color.BLUE,
				"edges");
		line2.addShapeMarkers(Shape.DIAMOND, Color.BLUE, 12);
		line2.addShapeMarkers(Shape.DIAMOND, Color.WHITE, 8);

		LineChart chart = GCharts.newLineChart(line1, line2);
		AxisLabels xAxis = AxisLabelsFactory.newAxisLabels(dates);
		chart.addXAxisLabels(xAxis);

		int it = 0;
		List<String> ylabels = new ArrayList<String>();
		while (it <= getYmax()) {
			ylabels.add(Integer.toString(it));
			it += getYpart();
		}

		AxisLabels yAxis = AxisLabelsFactory.newAxisLabels(ylabels);
		chart.addYAxisLabels(yAxis);

		return chart;
	}

	/**
	 * @return the width
	 */
	public Integer getWidth() {
		return width;
	}

	/**
	 * @param width
	 *            the width to set
	 */
	@Value("${chart.width}")
	public void setWidth(Integer width) {
		this.width = width;
	}

	/**
	 * @return the height
	 */
	public Integer getHeight() {
		return height;
	}

	/**
	 * @param height
	 *            the height to set
	 */
	@Value("${chart.height}")
	public void setHeight(Integer height) {
		this.height = height;
	}

	/**
	 * @return the graphDAO
	 */
	public GraphDAO getGraphDAO() {
		return graphDAO;
	}

	/**
	 * @param graphDAO
	 *            the graphDAO to set
	 */
	@Autowired
	public void setGraphDAO(GraphDAO graphDAO) {
		this.graphDAO = graphDAO;
	}

	/**
	 * @return the ymax
	 */
	public Integer getYmax() {
		return ymax;
	}

	/**
	 * @param ymax
	 *            the ymax to set
	 */
	@Value("${chart.ymax}")
	public void setYmax(Integer ymax) {
		this.ymax = ymax;
	}

	/**
	 * @return the ypart
	 */
	public Integer getYpart() {
		return ypart;
	}

	/**
	 * @param ypart
	 *            the ypart to set
	 */
	@Value("${chart.ypart}")
	public void setYpart(Integer ypart) {
		this.ypart = ypart;
	}

	/**
	 * @return the dozerUtil
	 */
	public DozerUtil getDozerUtil() {
		return dozerUtil;
	}

	/**
	 * @param dozerUtil
	 *            the dozerUtil to set
	 */
	public void setDozerUtil(DozerUtil dozerUtil) {
		this.dozerUtil = dozerUtil;
	}
}
